package com.game.logic.fighting.pve;

import akka.actor.ActorRef;
import com.coment.cfg.luban.RolesSkillCfg;
import com.coment.cfg.luban.Tables;
import com.coment.cfg.luban.constant.AIDCFG;
import com.coment.cfg.luban.items.PetCfg;
import com.coment.message.BuffInfo;
import com.coment.message.HurtInfo;
import com.coment.message.InjuryMessage;
import com.coment.po.Game;
import com.coment.po.UserPet;
import com.coment.po.roles.Roles;
import com.game.dao.core.GameDao;
import com.game.dao.user.UserPlayInfoDao;
import com.game.dao.user.pet.UserPetDao;
import com.game.dao.user.roles.RolesDao;
import com.game.framework.lock.annotation.WriteLock;
import com.game.logic.fighting.actor.RolesActor;
import com.game.logic.fighting.actor.SkillInfo;
import com.game.logic.fighting.attrs.FightingLogic;
import com.game.logic.fighting.formula.InjuryFormulaBase;
import com.game.logic.fighting.skill.hurt.HurtInfoEventHandler;
import com.xs.action.exection.ActionException;
import com.xs.build.server.websocket.channel.ClientManager;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

import java.util.Optional;

/// 战斗fw
@Slf4j
@Service
public class FightingService {
    @Resource
    private GameDao gameDao;

    @Resource
    private RolesDao rolesDao;

    @Resource
    private UserPetDao userPetDao;

    @Resource
    private UserPlayInfoDao userPlayInfoDao;

    @Resource
    private ApplicationEventPublisher eventPublisher;

    public void attack3(
            Integer anchorInfoId,
            String attacker,
            String[] targets
    ) {
        Game select = this.gameDao.findById(anchorInfoId).orElseThrow(
                () -> new RuntimeException("游戏不存在")
        );
        if (select.getStartTime() == null) {
            throw new ActionException("游戏未开始");
        }

        Roles att = rolesDao.findByIdMust(attacker);

        InjuryFormulaBase formulaBase = new InjuryFormulaBase(att);
        InjuryMessage injuryMessage = formulaBase.tryHurt();

        if (injuryMessage.verificationResults == null) {
            for (String targetId : targets) {
                // 攻击逻辑
                HurtInfo hurt = formulaBase.hurt3(rolesDao, targetId);
                injuryMessage.hurtInfoList.add(hurt);
            }
        }
        ClientManager.sendMessageToClient(anchorInfoId, injuryMessage);

        HurtInfoEventHandler.DoHurt doHurt = new HurtInfoEventHandler.DoHurt(this, attacker, injuryMessage.hurtInfoList);
        eventPublisher.publishEvent(doHurt);

        rolesDao.save(att);
    }


    @WriteLock(writeclass = Roles.class, parameterIndex = "#attacker")
    public void attack(
            Integer anchorInfoId,
            String attacker,
            String[] targets
    ) {
        Game select = this.gameDao.findById(anchorInfoId).orElseThrow(
                () -> new RuntimeException("游戏不存在" + anchorInfoId)
        );
        if (select.getStartTime() == null) {
            throw new ActionException("游戏未开始");
        }

        Roles att = rolesDao.findByIdMust(attacker);
        Integer cardId = att.getCardId();
        int index = att.getCardId() * 1000 + att.getSkillLv();
        RolesSkillCfg rolesSkillCfg = Tables.cfg.get_tbrolesskillcfg().get(index);

        boolean useSkill = false;
        if (cardId < 1000 && rolesSkillCfg.trigge == 1) {
            useSkill = tryUseSkill(anchorInfoId, attacker, targets, null);
        }

        if (!useSkill) {
            InjuryFormulaBase formulaBase = new InjuryFormulaBase(att);
            InjuryMessage injuryMessage = formulaBase.tryHurt();

            if (injuryMessage.verificationResults == null) {
                for (String targetId : targets) {
                    // 攻击逻辑
                    HurtInfo hurt = formulaBase.hurt(rolesDao, targetId);
                    injuryMessage.hurtInfoList.add(hurt);
                }
            }
            ClientManager.sendMessageToClient(anchorInfoId, injuryMessage);

            HurtInfoEventHandler.DoHurt doHurt = new HurtInfoEventHandler.DoHurt(this,
                    attacker,
                    injuryMessage.hurtInfoList
            );
            rolesDao.save(att);
            eventPublisher.publishEvent(doHurt);
        }
    }

    /// 释放-角色-技能
    public boolean tryUseSkill(
            Integer anchorInfoId,
            String rolesId,
            String[] effectOnTheEnemy,
            String[] effectOnFriendly
    ) {
        Game select = this.gameDao.findByIdMust(anchorInfoId);

        Roles roles = rolesDao.findByIdMust(rolesId);

        if (!select.userInfoIdSeat.containsValue(rolesId)) {
            throw new ActionException("角色不在游戏内" + rolesId);
        }

        RolesSkillCfg rolesSkillCfg = Tables.cfg.get_tbrolesskillcfg().get(roles.getCardId() * 1000 + roles.getSkillLv());
        int skillId = roles.getCardId();

        // 概率
        if (rolesSkillCfg.triggerRate / 100 < Math.random()) {
            return false;
        }


        SkillInfo skillInfo = new SkillInfo(anchorInfoId, rolesId, skillId, effectOnTheEnemy, effectOnFriendly);
        skillInfo.setCfg(rolesSkillCfg);
        RolesActor.getRolesActor(rolesId).tell(skillInfo, ActorRef.noSender());
        return true;
    }


    /// 释放宠物技能
    public void usePetSkill(
            Integer anchorInfoId, Integer userInfoId, String rolesId, String userPetId, String[] targetIds
    ) {
        UserPet userPet = verifyTheCombatStatusOfPets(userInfoId, userPetId);

        PetCfg petCfg = Tables.cfg.get_tbpetcfg().get(userPet.getPetId());
        int skillId = petCfg.skillId;

        Game select = this.gameDao.findByIdMust(anchorInfoId);

        Roles roles = rolesDao.findById(rolesId).orElseThrow();

        if (!select.userInfoIdSeat.containsValue(rolesId)) {
            throw new ActionException("角色不在游戏内");
        }

        RolesSkillCfg rolesSkillCfg = Tables.cfg.get_tbrolesskillcfg().get(roles.getCardId() * 1000 + roles.getSkillLv());

        SkillInfo skillInfo = new SkillInfo(
                anchorInfoId,
                rolesId,
                skillId,
                targetIds,
                null
        );
        skillInfo.setCfg(rolesSkillCfg);
        RolesActor.getRolesActor(rolesId).tell(skillInfo, ActorRef.noSender());
    }


    /// 校验宠物战斗状态
    public UserPet verifyTheCombatStatusOfPets(Integer userInfoId, String id) {
        UserPet byIdMust = userPetDao.findByIdMust(id);
        if (byIdMust.getUserInfoId() == userInfoId) {
            throw new ActionException("非该用户宠物");
        }
        int recentlyPlayedPetId = userPlayInfoDao.findByUserInfoIdOrCreate(userInfoId).getRecentlyPlayedPetId();
        if (byIdMust.getPetId() != recentlyPlayedPetId) {
            throw new ActionException("请先出战宠物");
        }
        return byIdMust;
    }

    public void skill10(Integer anchorInfoId, String attacker, String[] target) {
        Roles roles = rolesDao.findByIdMust(attacker);
        RolesSkillCfg rolesSkillCfg = Tables.cfg.get_tbrolesskillcfg().get(roles.getCardId() * 1000 + roles.getSkillLv());
        SkillInfo skillInfo = new SkillInfo(anchorInfoId, attacker, rolesSkillCfg.id, target, null);
        roles.rolePanel.fightPanel.clear();
        Optional<BuffInfo> first = roles.rolePanel.fightPanel.buff.stream()
                .filter(buff -> buff.sourceSkillId == rolesSkillCfg.id)
                .findFirst();

        if (first.isPresent()) {
            BuffInfo buff = first.get();
            Double hurt = buff.addValue.get(AIDCFG.shield);
            for (String defId : target) {

                Roles def = rolesDao.findByIdMust(defId);
                FightingLogic.beHarmed(def, hurt);
                HurtInfo hurtInfo = new HurtInfo();
                hurtInfo.rolesId = defId;
                hurtInfo.hurt = hurt;
                hurtInfo.hp = def.rolePanel.getAttribute().get(AIDCFG.hp);
                skillInfo.hurts.add(hurtInfo);

                log.debug("杨戬hurtInfo {}", hurtInfo);

                rolesDao.save(def);
            }

            // 移除护盾buff
            Double hp = roles.rolePanel.getAttribute().get(AIDCFG.hp);
            roles.rolePanel.fightPanel.buff.remove(buff);
            Double afterHp = roles.rolePanel.getAttribute().get(AIDCFG.hp);
            double updateValue = afterHp - hp;
            if (updateValue != 0) roles.rolePanel.fightPanel.fight.merge(AIDCFG.hp, -updateValue, Double::sum);
            rolesDao.save(roles);
        }
        rolesDao.save(roles);

        ClientManager.sendMessageToClient(anchorInfoId, skillInfo);
    }
}
